#ifndef HICONCURRENTQUEUE_HPP
#define HICONCURRENTQUEUE_HPP

#include <boost/thread.hpp>
#include <queue>

//See http://www.justsoftwaresolutions.co.uk/threading/implementing-a-thread-safe-queue-using-condition-variables.html
//FIXNOW: I don't really trust this code. Should test more throughly. Or implement my own (could port a nice Java no-lock queue).

namespace hi {
	
	template<typename Data>
	class ConcurrentQueue
	{
	private:
		std::queue<Data> the_queue;
		mutable boost::mutex the_mutex;
		boost::condition_variable the_condition_variable;
	public:
		void push(Data const& data);
		
		bool empty() const;
		
		bool tryPop(Data& popped_value);
		
		void waitAndPop(Data& popped_value);
		
	};
	
	template<typename Data>
	void ConcurrentQueue<Data>::push(Data const& data)
	{
		boost::mutex::scoped_lock lock(the_mutex);
		the_queue.push(data);
		lock.unlock();
		the_condition_variable.notify_one(); //FIXNOW notify all?
	}
	
	template<typename Data>
	bool ConcurrentQueue<Data>::empty() const
	{
		boost::mutex::scoped_lock lock(the_mutex);
		return the_queue.empty();
	}
	
	template<typename Data>
	bool ConcurrentQueue<Data>::tryPop(Data& popped_value)
	{
		boost::mutex::scoped_lock lock(the_mutex);
		if(the_queue.empty())
		{
			return false;
		}
		
		popped_value=the_queue.front();
		the_queue.pop();
		return true;
	}
	
	template<typename Data>
	void ConcurrentQueue<Data>::waitAndPop(Data& popped_value)
	{
		boost::mutex::scoped_lock lock(the_mutex);
		while(the_queue.empty())
		{
			the_condition_variable.wait(lock);
		}
		
		popped_value=the_queue.front();
		the_queue.pop();
	}
} // namespace hi


#endif